using System;
using Data;
using System.Collections.Generic;
using Locomotion;
using UnityEngine;
using UnityEngine.Events;
using Random = UnityEngine.Random;

namespace Bubbles
{
    public class MessageSpawner : MonoBehaviour
    {
        public static event Action<FixedBubbleInfo> NextMessageFixed;
        
        public int MessageCount { get; private set; }
        
        [SerializeField] private UnityEvent onMessageSpawnedLeft;
        [SerializeField] private UnityEvent onMessageSpawnedRight;
        
        [SerializeField] private Message messagePrefabLeft;
        [SerializeField] private Message messagePrefabRight;
        
        [SerializeField] private Transform spawnPositionLeft;
        [SerializeField] private Transform spawnPositionRight;
        
        private Message _currentMessage;
        private FixedBubbleInfo _currentFixedBubbleInfo;


        private void OnEnable()
        {
            GroundDetector.AnyCharacterGroundedChanged += GroundDetector_AnyCharacterGroundedChanged;
        }

        private void OnDisable()
        {
            GroundDetector.AnyCharacterGroundedChanged -= GroundDetector_AnyCharacterGroundedChanged;
        }

        [ContextMenu("Spawn Message")]
        public void Test()
        {
            ShowMessage("Spawn Message");
        }

        public bool CanShowMessage()
        {
            if (_currentMessage == null)
            {
                return false;
            }
            
            return _currentMessage.IsTyping;
        }
        
        public void ShowMessage(string text)
        {
            if (_currentMessage == null)
            {
                return;
            }

            if (_currentFixedBubbleInfo != null)
            {
                if (_currentFixedBubbleInfo.emojiAtTail != null && _currentFixedBubbleInfo.emojiAtTail.Length > 0)
                {
                    int fixedContentLen = _currentFixedBubbleInfo.content.Length;
                    int insertEmojiLen = fixedContentLen <= text.Length ? fixedContentLen : text.Length;
                    text = text.Insert(insertEmojiLen, _currentFixedBubbleInfo.emojiAtTail);
                    Debug.Log("insert emoji");
                }
            }
            _currentMessage.ShowMessage(text);

            switch (_currentMessage.Direction)
            {
                case Direction.Left:
                    onMessageSpawnedLeft?.Invoke();
                    break;
                case Direction.Right:
                    onMessageSpawnedRight?.Invoke();
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        public void DisablePreviousMessages()
        {
            Message[] messages = FindObjectsByType<Message>(FindObjectsSortMode.None);
            foreach (Message message in messages)
            {
                if (message == _currentMessage)
                {
                    continue;
                }

                message.enabled = false;
            }
        }
        
        private void GroundDetector_AnyCharacterGroundedChanged(GroundDetector.GroundChangedEventArgs groundChangedEventArgs)
        {
            if (groundChangedEventArgs.GroundDetector.IsGrounded)
            {
                Direction direction = Random.value < 0.5f ? Direction.Right : Direction.Left;
                CheckNextMessageFixed();
                SpawnMessage(direction);
            }
        }   

        private void SpawnMessage(Direction direction)
        {
            if (_currentFixedBubbleInfo == null)
            {
                SpawnRandomMessage(direction);
            }
            else
            {
                SpawnFixedMessage();
            }
            
            _currentMessage.ShowTyping();
            
            MessageCount++;
        }

        private void SpawnRandomMessage(Direction direction)
        {
            Message messagePrefab = direction switch
            {
                Direction.Left => messagePrefabLeft,
                Direction.Right => messagePrefabRight,
                _ => throw new ArgumentOutOfRangeException(nameof(direction), direction, null)
            };
            Vector3 spawnPosition = direction switch
            {
                Direction.Left => spawnPositionLeft.position,
                Direction.Right => spawnPositionRight.position,
                _ => throw new ArgumentOutOfRangeException(nameof(direction), direction, null)
            };
            
            _currentMessage = Instantiate(messagePrefab, spawnPosition, Quaternion.identity);
        }

        private void SpawnFixedMessage()
        {
            Direction direction = _currentFixedBubbleInfo.isLeft ? Direction.Left : Direction.Right;
            Message messagePrefab = direction switch
            {
                Direction.Left => messagePrefabLeft,
                Direction.Right => messagePrefabRight,
                _ => throw new ArgumentOutOfRangeException(nameof(direction), direction, null)
            };
            Vector3 spawnPosition = direction switch
            {
                Direction.Left => spawnPositionLeft.position,
                Direction.Right => spawnPositionRight.position,
                _ => throw new ArgumentOutOfRangeException(nameof(direction), direction, null)
            };
            _currentMessage = Instantiate(messagePrefab, spawnPosition, Quaternion.identity);
        }

        private void CheckNextMessageFixed()
        {
            var fixedBubbleData = ScriptableObjectHelper.GetFixedBubbleData();
            var fixedInfo = fixedBubbleData.listFixedBubbleInfo.Find(info => info.bubbleIndex == MessageCount + 1);
            _currentFixedBubbleInfo = fixedInfo;
            if (_currentFixedBubbleInfo != null)
            {
                Debug.Log($"get next fixed bubble info: {_currentFixedBubbleInfo.bubbleIndex}, {_currentFixedBubbleInfo.content}");
                NextMessageFixed?.Invoke(_currentFixedBubbleInfo);
            }
        }
    }
}
